package net.villonanny.entity;

import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.villonanny.ConversationException;
import net.villonanny.Translator;
import net.villonanny.Util;
import net.villonanny.type.LocalizedType;
import net.villonanny.type.ResourceType;
import net.villonanny.type.ResourceTypeMap;

import org.apache.log4j.Logger;

public abstract class UpgradeableSite {
	private final static Logger log = Logger.getLogger(UpgradeableSite.class);
	private ConstructionData constructionData;
	public Translator translator;

	protected UpgradeableSite(String name, String urlString, Translator translator) {
		this.translator = translator;
		constructionData = new ConstructionData(name, urlString, translator);
	}
	
	public LocalizedType getType() {
		return constructionData.getType();
	}

	public void setType(LocalizedType type) {
		constructionData.setType(type);
	}

	public void fetch(Util util) throws ConversationException {
		setUpgradeable(true);
		setFoodShortage(false);
		constructionData.setMaxLevelReached(false);
		
		Pattern p;
		Matcher m;
		String page = util.httpGetPage(getUrlString());
		// Level
		String level = translator.getMatchingPattern(Translator.LEVEL);
		p = Pattern.compile(String.format("(?s)(?i)<h1>(?:<b>)?.*? %s (\\d+)(?:</b>)?</h1>", level));
		m = p.matcher(page);
		if (m.find()) {
//			setTypeString(m.group(1)); Not needed anymore because typeString set when village fetches all slots [xtian]
			setCurrentLevel(m.group(1));
		} else {
			throw new ConversationException("Can't find level for \"" + this.getName() + "\"");
		}
		// Needed resources
		int lastPos=0;
		for (ResourceType resourceType : ResourceType.values()) {
			int res = resourceType.toInt() + 1; // Travian is 1-based
			p = Pattern.compile("(?s)(?i)<img .*? src=\".*?img/un/r/"+res+".gif\"[^>]*>(\\d\\d*) \\|");
			m = p.matcher(page);
			m.region(lastPos, page.length());
//			Util.saveTestPattern("fetch A", p, page);
			if (!m.find()){
				p = Pattern.compile("(?s)<img[^>]+class=\"r"+res+"\"[^>]*>\\s*(\\d+)\\s*\\|");
				m = p.matcher(page);
				m.region(lastPos, page.length());
//				Util.saveTestPattern("fetch B", p, page);
			}
			if (m.find()) {
				String stringNumber = m.group(1);
				lastPos = m.end();
				try {
					this.setNeededResource(resourceType, Integer.parseInt(stringNumber));
				} catch (NumberFormatException e) {
					throw new ConversationException("Invalid number for \"" + this.getName() + "\": " + stringNumber);
				}
			} else {
				// No resources found, we presume max level reached
//				if (getCurrentLevel()<10) { // TODO should be specific for the item (5 or 20 in some items)
//					throw new ConversationException("Can't find needed resources for \"" + this.getName() + "\"");
//				} else {
					log.debug("Max level reached");
					constructionData.setMaxLevelReached(true);
//				}
			}
		}
		// Check food needed
		lastPos=0;
		//p = Pattern.compile(String.format("(?s)(?i)<span class=\"c\">%s[^>]*</span>", translator.getMatchingPattern(Translator.FOOD_SHORTAGE)));
		p = Pattern.compile("(?s)(?i)"+translator.getMatchingPattern(Translator.FOOD_SHORTAGE));
		m = p.matcher(page);
		if (!m.find()) {
			// Needed time
			p = Pattern.compile("(?s)<img .*? src=\".*?img/un/a/clock.gif\"[^>]*>([^<]*)<");
			m = p.matcher(page);
			m.region(lastPos, page.length());
			if(!m.find()){
				p = Pattern.compile("(?s)<img[^>]*class=\"clock\"[^>]*>([^<]*)");
				m = p.matcher(page);
				m.region(lastPos, page.length());
			}
			if (m.find()) {
				String timeString = m.group(1).trim();
				this.setSecondsForNextLevel(Util.timeToSeconds(timeString));
			} else {
				if (getCurrentLevel()<10 && !constructionData.isMaxLevelReached()) { // TODO should be specific for the item (5 or 20 in some items)
					throw new ConversationException("Can't find time to complete " + this.getName());
				} else {
					log.debug("Max level reached");
					constructionData.setMaxLevelReached(true);
				}
			}
		} else {
			setFoodShortage(true);
		}
		if (!isUpgradeable()) {
			this.setSubmitUrlString(null);
			return;
		}
		// Find submit url
		int pos = m.end(); // Keep last matcher position
		p = Pattern.compile("(?s)<a href=\"(dorf\\d\\.php\\?.*?)\">");
		m = p.matcher(page);
		m.region(pos, page.length());
		if (m.find()) {
			String submitUrlString = m.group(1);
			this.setSubmitUrlString(Util.getFullUrl(this.getUrlString(), submitUrlString));
		} else {
			// No url because can't grow level
			this.setSubmitUrlString(null);
		}
	}
	
//	public String getTypeString() { 
//		return constructionData.getTypeString(); // e.g. "miniera di ferro"
//	}
	
//	public void setTypeString(String typeString) {
//		constructionData.setTypeString(typeString);
//	}

	public int getFoodNeeded() {
		return constructionData.getFoodNeeded();
	}
	
	public void setNeededResource(ResourceType type, int amount) {
		constructionData.setNeededResource(type, amount);
	}

	/**
	 * Return true if the item can be posted for upgrade
	 * @return
	 */
	public boolean isSubmittable() {
		return constructionData.isSubmittable();
	}
	
	public int getTotResourcesNeeded() {
		return constructionData.getTotResourcesNeeded();
	}

	public int getCurrentLevel() {
		return constructionData.getCurrentLevel();
	}

	public void setCurrentLevel(int currentLevel) {
		constructionData.setCurrentLevel(currentLevel);
	}

	public void setCurrentLevel(String currentLevel) throws ConversationException {
		constructionData.setCurrentLevel(currentLevel);
	}

	public int getNextLevel() {
		return constructionData.getNextLevel();
	}

	public void setNextLevel(int nextLevel) {
		constructionData.setNextLevel(nextLevel);
	}

	public int getSecondsForNextLevel() {
		return constructionData.getSecondsForNextLevel();
	}

	public void setSecondsForNextLevel(int secondsForNextLevel) {
		constructionData.setSecondsForNextLevel(secondsForNextLevel);
	}

	public String getName() {
		return constructionData.getName();
	}

	public String getUrlString() {
		return constructionData.getUrlString();
	}

	public String getSubmitUrlString() {
		return constructionData.getSubmitUrlString();
	}

	public void setSubmitUrlString(String submitUrlString) {
		constructionData.setSubmitUrlString(submitUrlString);
	}
	
	public ResourceTypeMap getNeededResources() {
		return constructionData.getNeededResources();
	}

	public void setUpgradeable(boolean upgradeable) {
		constructionData.setUpgradeable(upgradeable);
	}

	public void setFoodShortage(boolean foodShortage) {
		constructionData.setFoodShortage(foodShortage);
	}

	/**
	 * Return true if there are enough resources to upgrade and max level has not been reached;
	 * true doesn't mean this item is submittable.
	 * @return
	 */
	public boolean isUpgradeable() {
		return constructionData.isUpgradeable();
	}
	
	public Date upgrade(Util util) throws ConversationException {
		return constructionData.upgrade(util);
	}

	public String getCompletionTimeString(Util util, String page) throws ConversationException {
		return constructionData.getCompletionTimeString(util, page);
	}
	
	public boolean getFoodShortage() {
		return constructionData.getFoodShortage();
	}

	public boolean isMaxLevelReached() {
		return constructionData.isMaxLevelReached();
	}
	
	public Translator getTranslator() {
		return constructionData.getTranslator();
	}
	
	protected void setConstructionData(ConstructionData constructionData) {
		this.constructionData = constructionData;
	}
	
	public String toString() {
		return constructionData.toString();
	}

	abstract public boolean needsFieldsQueue();

//	public void setTypeString(LocalizedType type) {
//		constructionData.setTypeString(type);
//	}
}
